package com.collabscm.waf.util;

import java.io.Serializable;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Component;

import com.collabscm.waf.exception.ConfigurationException;
import com.collabscm.waf.solution.logging.Logger;
import com.collabscm.waf.solution.logging.LoggerFactory;

/**
 * BeanFactory的工具类，用户对Spring的BeanFactory进行封装并使用。
 *
 * @author Zeng Raoxing
 */
@Component
@DependsOn("beanFactoryProvider")
public class BeanFactoryUtils {
	private static Logger logger = LoggerFactory.getLogger(BeanFactoryUtils.class);
	/**
	 * Spring的容器，目的是减少Spring的反射注入。
	 */
	private static ApplicationContext applicationContext;
	/**
	 * 缓存Service实例的引用，此处为了
	 */
	private static Map<Class<?>, Serializable> cacheServices = new HashMap<Class<?>, Serializable>();
	/**
	 * 得到Bean的实例
	 * 
	 * @param <T>
	 * @param beanClass
	 */
	public static <T extends Serializable> T getBean(Class<T> beanClass) {
		@SuppressWarnings("unchecked")
		T bean = (T) cacheServices.get(beanClass);
		if(bean == null) {
			bean = getBeanFromContext(beanClass);
			cacheServices.put(beanClass, bean);
		}
		return bean;
	}

	/**
	 * 从ApplicationContext中获得Bean对象
	 * @param <T>
	 * @param beanClass
	 * @return
	 */
	private static <T> T getBeanFromContext(Class<T> beanClass) {
		Map<String, T> beanMap = applicationContext.getBeansOfType(beanClass);
		Collection<T> beans = beanMap.values();
		if(beans.size() == 0) {
			throw new ConfigurationException("无法查找到[" + beanClass + "]的实例。");
		} else if(beans.size() > 1) {
			logger.warn("共找到{}个{}的实例，系统仅能自动选择其中一个", beans.size(), beanClass);
		}
		//取Iterator的第一个值。
		T bean = beans.iterator().next();
		return bean;
	}
	
	public static class BeanFactoryProvider {
		/**
		 * 设置BeanFactoryUtils的ApplicationContext的实例
		 * 
		 * @param context
		 */
		protected void setApplicationContext(ApplicationContext context) {
			BeanFactoryUtils.applicationContext = context;
		}
		
	}

}
